package com.naiterui.ehp.bp.security.jwt;

import cn.hutool.core.util.StrUtil;
import com.naiterui.ehp.bp.security.properties.SecurityProperties;
import com.naiterui.ehp.bp.security.service.IOnlineUserService;
import com.naiterui.ehp.bp.security.service.UserCacheClean;
import com.naiterui.ehp.bp.security.vo.OnlineUserVO;
import io.jsonwebtoken.ExpiredJwtException;
import java.io.IOException;
import java.util.Objects;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

@Slf4j
@AllArgsConstructor
public class TokenFilter extends GenericFilterBean {

  private final TokenProvider tokenProvider;
  private final UserCacheClean userCacheClean;
  private final SecurityProperties securityProperties;
  private final IOnlineUserService onlineUserService;

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    String token = this.tokenProvider.resolveToken(httpServletRequest);
    // 对于 Token 为空的不需要去查 Redis
    if (StrUtil.isNotBlank(token)) {
      OnlineUserVO onlineUserVO = null;
      boolean cleanUserCache = false;
      try {
        onlineUserVO = this.onlineUserService.getOne(this.securityProperties.getOnlineKey() + token);
      } catch (ExpiredJwtException e) {
        log.error(e.getMessage());
        cleanUserCache = true;
      } finally {
        if (cleanUserCache || Objects.isNull(onlineUserVO)) {
          String userName = String.valueOf(this.tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY));
          this.userCacheClean.cleanUserCache(userName);
        }
      }
      if (onlineUserVO != null && StringUtils.hasText(token)) {
        Authentication authentication = this.tokenProvider.getAuthentication(token);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // Token 续期
        this.tokenProvider.checkRenewal(token);
      }
    }
    filterChain.doFilter(servletRequest, servletResponse);
  }

}
